#include <cstdlib>

#include "LoadShaders.h"

static const GLchar* ReadShader( const char* filename )
{
#ifdef WIN32
  FILE* infile;
  fopen_s( &infile, filename, "rb" );
#else
  FILE* infile = fopen( filename, "rb" );
#endif

  if( !infile ) {
    printf("ReadShader失败\n");
    return NULL;
  }

  fseek( infile, 0, SEEK_END );
  int len = ftell( infile );
  fseek( infile, 0, SEEK_SET );

  GLchar* source = new GLchar[len+1];

  fread( source, 1, len, infile );
  fclose( infile );

  return const_cast<const GLchar*>(source);
}

GLuint LoadShaders( ShaderInfo* shaders )
{
    if( shaders == NULL ) return 0;
    
    GLuint program = glCreateProgram();
    
    ShaderInfo* entry = shaders;
    while( entry->type != GL_NONE ) {
        GLuint shader = glCreateShader( entry->type );
        entry->shader = shader;
        const GLchar* source = ReadShader( entry->filename );
        if( source == NULL ) {
            for( entry = shaders; entry->type != GL_NONE; ++entry ) {
                glDeleteShader( entry->shader );
                entry->shader = 0;
            }
            return 0;
        }
        
        glShaderSource( shader, 1, &source, NULL );
        delete [] source;
        
        glCompileShader( shader );
        GLint compiled;
        glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
        if( !compiled ) {
            GLsizei len;
            glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &len );
            
            GLchar* log = new GLchar[len+1];
            glGetShaderInfoLog( shader, len, &len, log );
            std::cerr << "Shader compilation failed: " << log << std::endl;
            delete [] log;
            printf("compiled失败 %s\n", entry->filename);
            return 0;
        }
        glAttachShader( program, shader );
        ++entry;
    }
    
    glLinkProgram( program );
    
    GLint linked;
    glGetProgramiv( program, GL_LINK_STATUS, &linked );
    
    if ( !linked ) {
        for( entry = shaders; entry->type != GL_NONE; ++entry ) {
            glDeleteShader( entry->shader );
            entry->shader = 0;
        }
        return 0;
    }
    
    return program;
    
}
